﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using DDD;

namespace DevApp {
    public class Program4 : GameWindow {

        World wld;
        Graphics3D g3d;

        public Program4 ()
            : base (640, 480,
              new GraphicsMode (), "DDD: Transform Feedback Buffer", 0,
              DisplayDevice.Default, 3, 0,
              GraphicsContextFlags.ForwardCompatible | GraphicsContextFlags.Debug) {
        }

        protected override void OnLoad (System.EventArgs e) {
            var unifs = new UniformArray ();
            unifs.Add ("ModelViewMatrix", UniformArray.CurrentNode, () => ((Node)null).LocalToCamera);
            unifs.Add ("ProjectionMatrix", UniformArray.CurrentActiveCamera, () => ((Camera)null).ProjectionMatrix);

            var vert1 = new VertexShader ("Shaders/vertex-color.vert");
            var frag1 = new FragmentShader ("Shaders/vertex-color.frag");
            var sp1 = new ShaderProgram (vert1, frag1);


            var vert2 = new VertexShader ("Shaders/transform.vert");
            var frag2 = new FragmentShader ("Shaders/vertex-color.frag");
            var sp2 = new ShaderProgram (vert2, frag2);
            sp2.SetTransformFeedbackEnable (true, 1);
            sp2.SetFeedbackVarying (0, "f_Color");

            sp2.Compile ();

            var positions = new VertexArray<float> (4, 3);
            var colors1 = new VertexArray<float> (4, 3);
            var colors2 = new VertexArray<float> (4, 3);

            var positionData = new float[12]{1,-1,0,
                                             1,1,0,
                                             -1,-1,0,
                                             -1,1,0};
            positions.Set (0, 4, positionData);

            var colorData1 = new float[12]{1,0,0,
                                           1,0,0,
                                           1,0,0,
                                           1,0,0,};
            colors1.Set (0, 4, colorData1);

            var colorData2 = new float[12]{0, 1,0,
                                           0, 1,0,
                                           0, 1,0,
                                           0, 1,0,};
            colors2.Set (0, 4, colorData2);

            // 静的メッシュ
            var vbuf = new VertexBuffer ();
            vbuf.AddVertexArray ("v_Position", positions);
            vbuf.AddVertexArray ("v_Color", colors1);

            var indices = new int[6] { 0, 1, 2, 2, 1, 3 };
            var ibuf = new IndexBuffer<int> (PrimitiveType.Triangle, 2);
            ibuf.Set (0, 2, indices);

            var app1 = new Appearance ();
            app1.SetShaderProgram (sp1);
            app1.AddUniformArray (unifs);

            // 変形メッシュ
            var fbuf = new FeedbackBuffer ();
            fbuf.AddVertexArray ("f_Color", colors1, colors2);

            var vbuf2 = new VertexBuffer ();
            vbuf2.AddVertexArray ("v_Position", positions);
            vbuf2.AddVertexArray ("v_Color", colors2);

            var app2 = new Appearance ();
            app2.SetShaderProgram (sp2);
            app2.AddUniformArray (unifs);

            var msh = new Transformer ();
            msh.SetVertexBuffer (vbuf);
            //msh.SetIndexBuffer (ibuf);
            msh.SetAppearance (app1);
            msh.SetFeedbackBuffer (fbuf);
            msh.SetVertexBuffer (vbuf2);
            msh.SetAppearance (app2);


            var node1 = new Node ();
            node1.Attach (msh);
            node1.UserID = 101;


            var cam = new Camera ();
            cam.SetPerspective (45, Width / (float)Height, 0.1f, 100f);

            var node2 = new Node ();
            node2.Attach (cam);
            node2.SetTranslation (0, 0, 10);

            wld = new World ();
            wld.AddChild (node1);
            wld.AddChild (node2);
            wld.SetActiveCamera (node2);

            g3d = Graphics3D.GetInstance ();
            g3d.RenderPass += delegate {
                g3d.SetWorld (wld);
                g3d.SetClearColor (0, 0, 1, 1);
                g3d.SetClearDepth (1);
                g3d.SetColorClearEnabled (true);
                g3d.SetDepthClearEnabled (true);
                g3d.SetViewort (0, 0, Width, Height);
            };


            // 未実装
            VSync = VSyncMode.On;
        }

        protected override void OnUnload (EventArgs e) {
            wld = null;
            GC.Collect ();
            g3d.Release ();
        }

        protected override void OnUpdateFrame (FrameEventArgs e) {

        }

        protected override void OnRenderFrame (FrameEventArgs e) {

            g3d.Render ();

            SwapBuffers ();
        }

      
        [STAThread]
        public static void Main () {
            using (var example = new Program4 ()) {
                example.Run (30);
            }
        }
    
        
    }
}
